package com.atguigu.guli.service.ucenter.controller.api;

import com.atguigu.guli.common.util.HttpClientUtils;
import com.atguigu.guli.service.base.exception.GuliException;
import com.atguigu.guli.service.base.helper.JwtHelper;
import com.atguigu.guli.service.base.helper.JwtInfo;
import com.atguigu.guli.service.base.result.ResultCodeEnum;
import com.atguigu.guli.service.ucenter.entity.Member;
import com.atguigu.guli.service.ucenter.service.MemberService;
import com.atguigu.guli.service.ucenter.util.UcenterProperties;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpSession;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.UUID;

/**
 * @author helen
 * @since 2020/7/6
 */
//@CrossOrigin
@Controller//注意这里没有配置 @RestController
@RequestMapping("/api/ucenter/wx")
@Slf4j
public class ApiWxController {

    @Autowired
    private UcenterProperties ucenterProperties;

    @Autowired
    private MemberService memberService;

    /**
     * 生成二维码
     * @return
     */
    @GetMapping("login")
    public String genQrConnect(HttpSession session){

        String baseUrl = "https://open.weixin.qq.com/connect/qrconnect?" +
                "appid=%s" +
                "&redirect_uri=%s" +
                "&response_type=code" +
                "&scope=snsapi_login" +
                "&state=%s" +
                "#wechat_redirect";

        //redirect_uri：被微信服务器调用的本地接口地址
        String encodeUri = "";
        try {
            String redirectUri = ucenterProperties.getRedirectUri();
            encodeUri = URLEncoder.encode(redirectUri, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            //log.error(ExceptionUtils.getStackTrace(e));
            throw new GuliException(ResultCodeEnum.URL_ENCODE_ERROR);
        }

        //state：用于保持请求和回调的状态，授权请求后原样带回给第三方。该参数可用于防止csrf攻击
        String state = UUID.randomUUID().toString();
        System.out.println("生成的state = " + state);
        session.setAttribute("wx_open_state", state);

        //生成二维码的超链接
        String qrcodeUrl = String.format(
                baseUrl,
                ucenterProperties.getAppId(),
                encodeUri,
                state);

        //客户端跳转
        return "redirect:" + qrcodeUrl;
    }

    @GetMapping("callback")
    public String callback(String code, String state, HttpSession session){
        System.out.println("callback被调用");
        System.out.println("code = " + code);
        System.out.println("state = " + state);

        //一、校验code和state
        //1、非空校验
        if(StringUtils.isEmpty(code) || StringUtils.isEmpty(state)){
            //log.error("非法回调");
            throw new GuliException(ResultCodeEnum.ILLEGAL_CALLBACK_REQUEST_ERROR);
        }
        //2、从session中获取state进行校验
        String sessionState =  (String)session.getAttribute("wx_open_state");
        if(!state.equals(sessionState)){
            //log.error("非法回调");
            throw new GuliException(ResultCodeEnum.ILLEGAL_CALLBACK_REQUEST_ERROR);
        }


        //二、使用httpclient携带code获取access_token
        //1、组装请求url
        String accessTokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token";
//                "?appid=APPID" +
//                "&secret=SECRET" +
//                "&code=CODE" +
//                "&grant_type=authorization_code";
        HashMap<String, String> accessTokenParam = new HashMap<>();
        accessTokenParam.put("appid", ucenterProperties.getAppId());
        accessTokenParam.put("secret", ucenterProperties.getAppSecret());
        accessTokenParam.put("code", code);
        accessTokenParam.put("grant_type", "authorization_code");
        //2、创建httpclient对象
        HttpClientUtils client = new HttpClientUtils(accessTokenUrl, accessTokenParam);


        String result = "";
        try {
            //3、发送请求
            client.setHttps(true);
            client.get();
            //4、得到响应
            result = client.getContent();
            System.out.println(result);
        } catch (Exception e) {
            //log.error("获取access_token失败：" + ExceptionUtils.getStackTrace(e));
            throw new GuliException(ResultCodeEnum.FETCH_ACCESSTOKEN_FAILD);
        }

        //5、解析json结果
        Gson gson = new Gson();
        HashMap<String, Object> resultMap = gson.fromJson(result, HashMap.class);
        //xml：dom4j <errcode></errcode><errmsg></errmsg>

        //6、判断业务失败
        Object errcodeObj = resultMap.get("errcode");
        Object errmsgObj = resultMap.get("errmsg");
        if(errcodeObj != null){
            Double errorCode = (Double)errcodeObj;
            String errorMsg = (String)errmsgObj;
            //log.error("获取access_token失败：" + errorCode + "，" + errorMsg);
            throw new GuliException(ResultCodeEnum.FETCH_ACCESSTOKEN_FAILD);
        }

        //7、获取access_token和openid
        String accessToken = (String)resultMap.get("access_token");
        String openid = (String)resultMap.get("openid");

        System.out.println("access_token = " + accessToken);
        System.out.println("openid = " +  openid);

        //三、查询用户是否存在：存在（数据库中查询用户信息）、不存在（调用远程接口查找用户信息，注册）
        Member member = memberService.getByOpenId(openid);
        if(member == null){


            //四、携带access_token获取用户信息
            //1、组装请求url
            String baseUserInfoUrl = "https://api.weixin.qq.com/sns/userinfo" +
                    "?access_token=" + accessToken +
                    "&openid=" + openid;
            //2、创建httpclient对象
            client = new HttpClientUtils(baseUserInfoUrl);

            String resultUserInfo = "";
            try {
                //3、发送请求
                client.setHttps(true);
                client.get();
                //4、得到响应
                resultUserInfo = client.getContent();
            } catch (Exception e) {
                //log.error("获取用户信息失败：" + ExceptionUtils.getStackTrace(e));
                throw new GuliException(ResultCodeEnum.FETCH_USERINFO_ERROR);
            }
            //5、解析响应结果
            HashMap resultUserInfoMap = gson.fromJson(resultUserInfo, HashMap.class);

            //6、处理业务失败
            errcodeObj = resultUserInfoMap.get("errcode");
            errmsgObj = resultUserInfoMap.get("errmsg");
            if(errcodeObj != null){
                Double errorCode = (Double)errcodeObj;
                String errorMsg = (String)errmsgObj;
                //log.error("获取用户信息失败：" + errorCode + "，" + errorMsg);
                throw new GuliException(ResultCodeEnum.FETCH_USERINFO_ERROR);
            }

            //7、从结果中获取用户信息
            String nickname = (String)resultUserInfoMap.get("nickname");
            String headimgurl = (String)resultUserInfoMap.get("headimgurl");
            Double sex = (Double)resultUserInfoMap.get("sex");

            //将用户头像存储在oss服务器上
            //得到oss服务器上的头像地址

            //五、将用户信息插入到数据库，完成用户注册
            member = new Member();
            member.setOpenid(openid);
            member.setNickname(nickname);
            member.setAvatar(headimgurl);//存储oss服务器上的头像地址
            member.setSex(sex.intValue());
            memberService.save(member);
        }

        //六、生成jwt完成用户登录
        JwtInfo jwtInfo = new JwtInfo();
        jwtInfo.setId(member.getId());
        jwtInfo.setNickname(member.getNickname());
        jwtInfo.setAvatar(member.getAvatar());
        String token = JwtHelper.createToken(jwtInfo);

        return "redirect:http://192.168.123.100:3000?token=" + token;
    }
}
